Step 3 - Create and load locale packs

A locale pack is a .kzb file that contains only the resources of a specific locale. Using Kanzi Engine API you can load the application resources used by a certain locale only when you need them, and unload the resources that the application does not need. That way only the resources used by the current locale occupy the device memory.

In this step of the tutorial you first prepare the Kanzi Studio project for loading additional locales and create locale packs for Japanese and Chinese locales which contain only the resources used by each of those locales. You then use the Kanzi Engine API to load the locale packs when a user clicks a button in the Kanzi application.

Prepare the Kanzi Studio project for loading additional locales

In this section you make a few modifications to the Kanzi Studio project you created in the first two steps of the tutorial. You import fonts that support the locales you add in this step of the tutorial, prepare the project so that instances of the LocaleButton prefab in the LocaleSelector use a custom property to control the locale of the application, add a control for loading additional locales, and you create aliases that allow you to readily access the project nodes using the Kanzi Engine API.

To prepare the project for loading additional locales:

  1. Select File > Import > Import Fonts and import fonts that include the Japanese and Chinese glyphs. See Importing fonts.
    For example, import the NotoSansCJKjp-Regular.otf and NotoSansCJKsc-Regular.otf
  2. Note that in order to properly render text content you have to use a font that includes the glyphs of the languages you want to include in your Kanzi application.

  3. In the Library press Alt and right-click Property Types and select Property Type.
  4. In the New Property Type window set:

    Click Save.
    You use this custom property type to set the locale using the buttons in the LocaleSelector node.

  5. In the Project > Prefabs select the LocaleButton prefab and in the Properties add the LocaleID property.
  6. In the Project > Prefabs select the LocaleButton, in the Triggers add the Button: Click trigger, add the Set Property Value action, and set:
  7. Click Save.
  8. In the Project in the LocaleSelector node for each LocaleButton prefab instance:
    1. In the Properties add the LocaleID property and set it to the locale you want to set with this button.

      For example, to set to default locale, in this case English, select the Invariant Language (Invariant Country) () value.
    2. In the Triggers right-click the Button: Click trigger and select Remove Trigger.
      This way you replace the trigger that defined the locale to which the trigger switches in each instance of the prefab with a trigger defined in the prefab that gets the value for the locale from the LocaleID property of each prefab instance.
  9. Repeat the previous step for each instance of the LocaleButton in the LocaleSelector node:
  10. In the Project press Alt and right-click the Viewport 2D node, select Button 2D, name it LoadLocales:
  11. In the Project press Alt and right-click the LoadLocales node, select Text Block 2D, name it Load locales....
  12. In the Project press Alt and right-click the LocaleSelector node, and select Alias.
    You use this alias to access the LocaleSelector node using the Kanzi Engine API and to add to the node the buttons to load the locales from the locale packs you prepare in the next section of this step.

Create locale packs

A locale pack is a .kzb file that contains only the resources of a specific locale.

In this section you add to the project localized resources for Japanese and Chinese locales, create styles which use the fonts that contain the glyphs of these locales, and create locale packs. In the next section you use the Kanzi Engine API to load the locale packs.

In the <KanziWorkspace>/Tutorials/Localization/Assets/Text you can find the .po files that contain all the text strings used in the Kanzi Studio project in this tutorial localized to Japanese and Chinese.

To create locale packs:

  1. In the Library > Localization right-click the Localization Table (Main) localization table, select Import Localization Table Manually, go to <KanziWorkspace>/Tutorials/Localization/Assets/Text, and import the Localization Table_jp_JP.po and Localization Table_zn_HANS.po .po files that contain the text strings for the Japanese and Chinese locales.
    Kanzi Studio creates locale specified in the .po files and adds the translations from the .po files to the localization table.
  2. Create the text resource that you use to display the name of the locale in the LocaleButton node:
    1. In the Library > Localization double-click the Localization Table (Main) localization table to open it the Localization Editor.
    2. Click , select Create New > Text, and name the new text resource LocaleDisplayName.
      You use the Kanzi Engine API to set this text resource to show the name of the locale in the LocaleButton that you use to load that locale.
    3. In the column for each locale the resources of which you load from their own locale packs, double-click the LocaleDisplayName cell, enter the text you want to show in the LocaleButton for each locale, and press the Enter key.
      Because you want the users of this locale to find their locale, use the native name of the locale. For example, for Japanese use 日本語, and for Chinese use 中文.
  3. Create the styles that set the font for each locale, because the Kanzi default font does not contain the Japanese and Chinese glyphs:
    1. In the Localization Table (Main) click , select Create New > Named Style, and name the new style LocaleStyle.
    2. In the Library > Styles right-click the LocaleStyle and select Duplicate and name the style after the locale where you use it.
      For example, name the style for the Japanese locale LocaleStyle-jp.
    3. In the Properties add the Font property and set it to the font that contains the glyphs of the language of the locale that uses the style.
      For example, for the Japanese locale set the Font property to the NotoSansCJKjp-Regular.otf font.
    4. Repeat the previous two steps as many times as you have locale packs you want to load in your Kanzi application.
      For example, repeat the previous two steps to create the style for the Chinese locale, name the style LocaleStyle-zn, and set the Font property to the NotoSansCJKsc-Regular.otf font.
      In the next section of this tutorial you use these styles to also display the name of the locale in the LocaleButton node using the correct font.
    5. In the Localization Table in the column for each locale where you want to apply the styles you created, double-click the LocaleStyle cell and select the style you want to apply to that locale.
      For example, for the Japanese locale select LocaleStyle-jp , and for Chinese locale select LocaleStyle-zn. The Finnish and German locales use the LocaleStyle which uses the default font.
    6. In the Project > Prefabs select the App > Model > Description node, in the Properties add the Style property and set it to <ResourceID> and the resource ID to LocaleStyle.
      This way you apply the styles you created to the nodes where you want to use it.
  4. In the Localization Table (Main) localization table click next to the locale name of the Japanese and Chinese locales.
    This way you mark the locales for which you want to create a locale pack .kzb file that contains only the resources used by that locale. Kanzi Studio does not export to the main .kzb file the resources of locales marked in the localization table as locale packs.
  5. In Kanzi Studio select File > Export KZB > Export Locale KZBs. This command:

    Tip If you want to export the entire Kanzi Studio project to a single .kzb file, including the resources of locales you mark as locale packs, select File > Export KZB > Export KZB Binary.

Load the locale packs

In this section you use the Kanzi Engine API to load the locale packs you created in the previous section. The application loads the locale packs when a user clicks the LoadLocales button you created in the beginning of this tutorial step, and triggers the loading of the locale packs for all locales stored in the <KanziWorkspace>/Projects/<ProjectName>/Application/bin/Locale_packs directory.

To load the locale packs:

  1. In Windows Explorer in the <ProjectName>/Application/bin/Locale_packs create binaries.cfg file and add to it the location and name of each .kzb file that contains a locale pack you want to load. Add the name of only one .kzb on each line.
    For example, if you created a locale pack for the Japanese and Chinese locales, and used jp-JP locale name for the Japanese locale and zn-Hans locale name for the Chinese locale, create the binaries.cfg, open it in a text editor, add the names of these two locale pack files to the binaries.cfg file, and save the file.
    jp-JP.kzb
    zh-Hans.kzb
  2. In Visual Studio open the Visual Studio solution for your application located in <ProjectName>/Application/configs/platforms/win32.
  3. In Visual Studio in the Solution Explorer right-click the Localization project and select Set as StartUp Project.
  4. In Visual Studio open the localization.cpp file and include fstream so that you can read the binaries.cfg file that contains the list of additional locales.
    #include <fstream>
  5. In this tutorial you use the custom property types defined in the Kanzi Studio project. To access these custom property types create a DynamicPropertyType and use the same name that is used in the Kanzi Studio project.
    class LocalizationApplication: public ExampleApplication
    {
    ...
    	// Type of the shared pointer for the custom property type defined
    	// in the Kanzi Studio project.
    	typedef std::shared_ptr<DynamicPropertyType<std::string> > StringDynamicPropertyTypeSharedPtr;
  6. In the LocalizationApplication class after the onProjectLoaded function implement the onLoadAdditionalLocalesButtonClicked event handler for the Button 2D click message from the LoadLocales node.
    When the user clicks the LoadLocales button, this event handler loads the resources for the locale pack .kzb files stored in the Locale_packs directory, and adds the locales to the project.
    void onLoadAdditionalLocalesButtonClicked(Button2D::ClickedMessageArguments& /*messageArgs*/)
    {
    	// Set the name of the directory where you stored the locale packs.
    	static const std::string localizationFolderName = "Locale_packs";
    
    	// Get the Screen node in the .kzb binary. You use the Screen node to access
    	// all the other nodes and resources in the .kzb binary.
    	ScreenSharedPtr screen = getScreen();
    	// Domain is a collection of all subsystems and contains the Kanzi resource manager.
    	// You need to get the resource manager to access the resources in the .kzb file.
    	ResourceManager* resourceManager = getDomain()->getResourceManager();
    
    	// Get the LocaleSelector node which contains the locale selection buttons.
    	Node2DSharedPtr localeSelector = screen->lookupNode<Node2D>("#LocaleSelector");
    
    	// Get the LocaleButton prefabricated template used for the buttons that set the locale.
    	// Get the reference to the template using the .kzb URL.
    	// When you use the full path of a resource, start the path with kzb:// followed by the project name and the location of the resource.
    	PrefabTemplateSharedPtr localeButtonPrefab = resourceManager->
    		acquireResource<PrefabTemplate>("kzb://localization/Prefabs/LocaleButton");
    
    	// Get the custom property type for setting the name of the locale in the
    	// LocaleButton node. You created this custom property type in the Kanzi Studio project.
    	StringDynamicPropertyTypeSharedPtr localeNameProperty =
    		StringDynamicPropertyTypeSharedPtr(new DynamicPropertyType<std::string>("LocaleName"));
    
    	// Get the custom property type for setting the locale in the application.
    	// You created this custom property type in the Kanzi Studio project.
    	StringDynamicPropertyTypeSharedPtr localeIdProperty =
    		StringDynamicPropertyTypeSharedPtr(new DynamicPropertyType<std::string>("LocaleID"));
    
    	// Read the binaries.cfg file that contains the list of the .kzb files
    	// that contain the locale packs.
    	std::string configFileName = localizationFolderName + "/binaries.cfg";
    	std::ifstream binariesConfigFileStream(configFileName.c_str());
    
    	std::string binaryFileName;
    
    	// Load the resources stored in the locale pack .kzb files.
    	while (getline(binariesConfigFileStream, binaryFileName))
    	{
    		// Create the path for the .kzb file.
    		std::string localizationKzbFilePath = localizationFolderName + "/" + binaryFileName;
    
    		// Add the .kzb file to the Kanzi resource manager.
    		KzuBinaryDirectory* binaryDirectory =
    			resourceManager->addDirectoryFromFile(localizationKzbFilePath);
    
    		// Load the locale resources from the .kzb file.
    		Screen::LocaleContainer locales = screen->registerLocales(*binaryDirectory);
    
    		// For each loaded locale pack add a button to the LocaleSelector node
    		// When you click the button, you change the application locale to the
    		// locale defined by the LocaleID property.
    		for (Screen::LocaleContainer::const_iterator it = cbegin(locales),
    			end = cend(locales); it != end; ++it)
    		{
    			std::string localeId = it->first;
    			ResourceDictionarySharedPtr localeDictionary = it->second;
    
    			// Instantiate the LocaleButton prefab.
    			Node2DSharedPtr localeButton =
    				localeButtonPrefab->instantiate<Node2D>("LocaleButton_" + localeId);
    
    			// Get the name of the locale that is shown in the application from the
    			// resource ID LocaleDisplayName stored in the localization table in the locale pack.
    			TextResourceSharedPtr localeDisplayNameResource =
    				localeDictionary->acquire<TextResource>(ResourceID("LocaleDisplayName"));
    
    			// Set the LocaleName property so that the Text Block 2D node in the button shows the name of the locale.
    			localeButton->setProperty(*localeNameProperty, localeDisplayNameResource->getText());
    			// Set the LocaleID property so that when you click the button the application changes to that locale.
    			localeButton->setProperty(*localeIdProperty, localeId);
    			
    			// Set the style of the Text Block 2D node in the button so that it sets
    			// the correct font for the LocaleDisplayName of the locale.
    			// Use this approach only to apply a style from the locale pack without changing the locale
    			// in the application.
    			optional<string> localeStyle = localeDictionary->find(ResourceID("LocaleStyle"));
    			localeButton->setStyleResourceID(ResourceID(*localeStyle));
    
    			// Add the LocaleButton node to the LocaleSelector node.
    			localeSelector->addChild(localeButton);
    		}
    	}
    
    	// After loading the locales from the locale packs, hide the button for
    	// loading the locale packs.
    	Button2DSharedPtr loadAdditonalLanguagesButton =
    		screen->lookupNode<Button2D>("#LoadLocales");
    	loadAdditonalLanguagesButton->setVisible(false);
    }
  7. In the LocalizationApplication class in the onProjectLoaded function get the button that contains the trigger that loads locale packs and register the event handler for the Button: Click message of the button.
    virtual void onProjectLoaded() KZ_OVERRIDE
    {
    ...
    	// Get the LoadLocales Button 2D node for loading additional locales.
    	Button2DSharedPtr LoadLocalesButton = getScreen()->
    		lookupNode<Button2D>("#LoadLocales");
    
    	// Register the message handler for the Button: Click message used by the
    	// LoadLocales node.
    	LoadLocalesButton->addMessageFilter(Button2D::ClickedMessage,
    		std::bind(&LocalizationApplication::onLoadAdditionalLocalesButtonClicked,
    		this, std::placeholders::_1));
  8. In Visual Studio select one of the solution configurations for your version of Visual Studio and run your application.
    For example, if you are still developing your application, select the GL_vs2010_Debug configuration. If you want to create a production version of your Kanzi application, select one of the available release configurations.
  9. In the application when you click the LoadLocales button, Kanzi loads the locale packs from the .kzb files listed in the binaries.cfg file, and in the LocaleSelector node instantiates one LocaleButton prefab for each locale.

< PREVIOUS STEP

What's next?

In this tutorial you learned how to localize Kanzi applications and use in your applications additional .kzb files that contain only localized resources for locales. To take this tutorial further, you can use the localization table .pot template to translate the content of this Kanzi application to additional languages. Additionally, you can create other resource types and create different resources for different locales. For example, create several animations and use each for a different locale:

See also

To find out more about how to localize your Kanzi applications, see Localization.

To learn about how Kanzi handles resources, see Resource management.

To learn more about how to use resource dictionaries, see Resources.

To learn more about managing your Kanzi Studio projects, see Projects.

To learn more about creating Kanzi applications, see Tutorials.

To find out more about Kanzi Studio features, see Working with ....